import { IRect } from '../base/Rect.js';
import { FIImage } from './FIImage.js';

export interface FIIAnimationFrame {
  readonly source: CanvasImageSource;
  readonly rect: IRect;
  readonly duration: number;
}
export interface FIIAnimationFrames {
  readonly name: string;
  readonly frames: FIIAnimationFrame[];
  readonly loop: number;
  readonly next?: string;
}
export class FIAnimationFramesPool {
  protected _framesMap: { [x in string]?: FIIAnimationFrames } = {}

  findFrames(name: string): FIIAnimationFrames | undefined {
    return this._framesMap[name];
  }
  addFrames(frames: FIIAnimationFrames) {
    this._framesMap[frames.name] = frames;
    return this;
  }

  static _inst?: FIAnimationFramesPool;
  static get() {
    if (!this._inst) {
      this._inst = new FIAnimationFramesPool;
    }
    return this._inst;
  }
}

export class FIAnimation extends FIImage {
  private _pool = FIAnimationFramesPool.get();
  private _frames?: FIIAnimationFrames;
  private _time: number = 0;
  private _playing: boolean = false;
  private _frameIdx: number = 0;
  private _loopCount?: number = 0;

  play(name?: string): FIAnimation {
    if (typeof name === 'string') {
      this._frames = this._pool.findFrames(name);
      this._loopCount = this._frames?.loop;
    }
    this._time = 0;
    this._playing = true;
    this._frameIdx = 0;
    return this;
  }
  stop(): FIAnimation {
    this._time = 0;
    this._playing = false;
    return this;
  }
  update(dt: number): void {
    if (!this._playing || !this._frames) {
      return;
    }
    const frames = this._frames;
    const framesLen = frames.frames.length;
    if (this._frameIdx >= framesLen) {
      return;
    }

    const frame = frames.frames[this._frameIdx];
    this.source = frame.source;
    this.sourceRect = frame.rect;
    this._time += dt;
    while (this._time > frame.duration) {
      this._time -= frame.duration;
      this._frameIdx++;
      if (this._frameIdx < framesLen) {
        continue;
      }
      if (this._loopCount) {
        this._loopCount--;
        this._frameIdx = 0;
      }
      if (this._loopCount) {
        continue;
      }
      this._playing = typeof frames.next === 'string';
      if (this._playing) {
        this._frames = this._pool.findFrames(frames.next!);
        this._loopCount = this._frames?.loop;
        this._frameIdx = 0;
      }
    }
  }
}
